#include <iostream>
#include <string>
#include<memory>

using namespace std;

class Car
{
public:
    Car(string name):_name(name){}
    virtual void show() = 0; //定义纯虚函数，子类必须实现

protected:
    string _name;

private:
};
class BMW:public Car
{
public:
    // 使用Car(name)类似于_name(name)，还是用了Car的_name，
    // 子类继承父类的构造函数可以参考 https://blog.csdn.net/aquapisces/article/details/104371658
    BMW(string name) : Car(name){};
    void show()
    {
        cout << "获取了一辆宝马汽车" << _name << endl;
    } 
protected : 
private:
};
class Audi : public Car
{
public:
    // 使用Car(name)类似于_name(name)，还是用了Car的_name，
    // 子类继承父类的构造函数可以参考 https://blog.csdn.net/aquapisces/article/details/104371658
    Audi(string name) : Car(name){};
    void show()
    {
        cout << "获取了一辆奥迪汽车" << _name << endl;
    }

protected:
private:
};

class Light
{
public:
    virtual void show() = 0;
};

class BMWLight:public Light
{
public:
    void show()
    {
        cout << "BMW light!" << endl;
    }
};

class AudiLight : public Light
{
public:
    void show()
    {
        cout << "Audi light!" << endl;
    }
};
/*
抽象工厂，对一组关联关系的产品簇提供产品对象的统一创建。
有点类似于工厂方法
*/
class AbstractFactory
{
public:
    virtual Car *createCar(string name) = 0;
    virtual Light *createCarLight() = 0;
};
class BMWFactory : public AbstractFactory
{
public:
    Car *createCar(string name)
    {
        return new BMW(name);
    }
    Light *createCarLight()
    {
        return new BMWLight();
    }
};
class AudiFactory : public AbstractFactory
{
public:
    Car *createCar(string name)
    {
        return new Audi(name);
    }
    Light *createCarLight()
    {
        return new AudiLight();
    }
};

int main()
{

    // 抽象工厂方法
    unique_ptr<AbstractFactory> bmwFactory(new BMWFactory);
    unique_ptr<AbstractFactory> audiFactory(new AudiFactory);
    unique_ptr<Car> p1(bmwFactory->createCar("X6"));
    unique_ptr<Car> p2(audiFactory->createCar("A8"));
    unique_ptr<Light> l1(bmwFactory->createCarLight());
    unique_ptr<Light> l2(audiFactory->createCarLight());

    p1->show();
    p2->show();
    l1->show();
    l2->show();

    return 0;
}